---
title: Add custom native code
description: Learn how to add custom native code to your Expo project.
---

import { Terminal } from '~/ui/components/Snippet';

Expo projects can use both third-party React Native libraries with native code and your own custom native code. Creating a [development build](/workflow/overview/#development-builds) allows you to include your specific native dependencies and customizations and not only what comes with the latest [Expo SDK](/versions/latest/). These native customizations can be any React Native library or your own custom native code.

For most third-party native libraries, [autolinking](/modules/autolinking/) makes it easy. All you have to do is install the npm package and run [prebuild](/workflow/prebuild/) to use the module. Some modules might also need a [config-plugin](/config-plugins/introduction) for additional native customizations. When adding your own custom native code, the approach varies based on how you want to work with native code.

## Create a local module with the Expo Modules API

By default, Expo projects use [Continuous Native Generation (CNG)](/workflow/continuous-native-generation). This means that projects do not have **android** and **ios** directories containing the native code and configuration. Instead, the native directories are generated right before building the app and are based on your [app config](/workflow/configuration) and native modules in **package.json**. This simplifies the management and upgrading of native code.

It might seem you cannot add custom native code to a project using CNG. However, you can still add that by [creating a local Expo module](/modules/get-started/#creating-the-local-expo-module).

Local Expo Modules function similarly to [Expo Modules](/modules/overview/) used by library developers and within the Expo SDK. They are not published to npm. Instead, you create them directly inside your project.

Creating a local module allows you to write custom Swift and Kotlin code that you can interact with from your JavaScript code. It is also included in the development builds and production apps automatically when you build with [EAS Build](/build/introduction) or when you [compile your app locally](/guides/local-app-development/#local-app-compilation).

## Manage custom native projects

You can opt out of CNG and directly manage the code and configuration inside your **android** and **ios** directories. To generate these directories, run `npx expo prebuild` or [compile your app locally](/guides/local-app-development/#local-app-compilation) (`npx expo run:android` or `npx expo run:ios`). You can also create a development build before compiling your app locally. To do so, run `npx expo install expo-dev-client` before `prebuild` or `run`.

<Terminal
  cmd={[
    '# Build your native Android project',
    '$ npx expo run:android',
    '',
    '# Build your native iOS project',
    '$ npx expo run:ios',
  ]}
  cmdCopy="npx expo run:android && npx expo run:ios"
/>

- `npx expo run:android` requires Android Studio and the Android SDK to be installed. See how to [setup environment](/guides/local-app-development/#android).
- `npx expo run:ios` requires Xcode (macOS only) installed on your computer. See how to [setup environment](/guides/local-app-development/#ios).

The `run` commands will [prebuild](/workflow/prebuild/) your project to generate all the native code within your project directory. If you manually modify the **android** or **ios** directory, you cannot re-run `npx expo prebuild` safely, as this may overwrite your changes.

If you install a library with Expo [config plugin](/config-plugins/introduction/), you'll need to follow a few steps:

- Add the plugin to the [`plugins`](/versions/latest/config/app/#plugins) array in the project's app config.
- Re-run `npx expo prebuild` to sync the changes before rebuilding the native app. This process often involves tasks like adding required permissions to the **AndroidManifest.xml** or **Info.plist**.
- For complex plugins, consider running `npx expo prebuild --clean`. This command will delete and re-generate the native directories from scratch.

### Manual changes to the native project files

If you manually modify the **android** and **ios** directories, you must set up new libraries manually. Running `npx expo prebuild` may not work as expected because the project is now in an unpredictable state (think of this like running `yarn` after manually modifying your **node_modules** directory).

If you want to make static changes to your native project files, such as **AndroidManifest.xml** or **Info.plist**, and still have access to prebuilding, then create a [config plugin](/config-plugins/plugins-and-mods/#create-a-plugin) to see how you can hook into the prebuild process to make those changes.

### Revert changes from `npx expo run:[android|ios]`

Suppose you have decided to roll your app back to being fully managed (no **android** or **ios** directories in your project directory). In that case, you can check out your most recent commit before executing `npx expo run:[android|ios]`, then run `npm install` again to restore the state of your **node_modules** directory.

### Develop apps with custom native code

Once you have customized the native code in your project, you can use the [`expo-dev-client`](/develop/development-builds/introduction/#what-is-an-expo-dev-client) library to [create a development build](/develop/development-builds/create-a-build/) and retain the convenience of working with JavaScript or TypeScript in Expo Go.

## Release apps with custom native code to production

When you're ready to ship your app, you can [build it with EAS Build](/build/introduction) the same as you were building it before adding custom native code. Alternatively, you can archive and sign it locally. Unsurprisingly, we recommend EAS Build!

<Terminal
  cmd={['# Install the CLI', '$ npm i -g eas-cli', '', '# Build your app!', '$ eas build -p all']}
  cmdCopy="npm i -g eas-cli && eas build -p all"
/>

## Create reusable native modules

Apart from adding custom native code to a project, the [Expo Modules API](/modules/overview) enables developers to build reusable modules for Expo and React Native projects using Swift, Kotlin, and TypeScript. These modules are often published to npm. They can also be included as separate packages within a [monorepo](/guides/monorepos/). We use the Expo Modules API for most modules in the [Expo SDK](/versions/latest).

Another option is to use [React Native's Core Native Modules API](https://reactnative.dev/docs/native-modules-intro), which may require some C++ knowledge in addition to Objective-C and Java. Most React Native modules in the ecosystem are built using this API because it is and always has been part of React Native. The Expo Module API is new and intends to solve many of the pain points of using the core API.
